package cn.jinjimi.app.util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.media.ExifInterface;
import android.util.Base64;
import android.util.Log;

import cn.jinjimi.base.util.FileUtils;
import cn.jinjimi.base.util.IOUtils;
import cn.jinjimi.base.util.LogUtil;
import cn.jinjimi.domain.data.Cache;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;

/**
 * Created by Roy
 * Date: 15/8/11
 */
public class BitmapUtils {

    private static final int MAX_K_SIZE = 200;// 对正常图片的压缩质量
    private static final int MAX_K_LONG_SIZE = 1024;// 对长图的压缩
    private static final int MAX_HEIGHT = 1280;
    private static final int MAX_WIDTH = 720;

    /**
     * Note: this method may return null
     *
     * @param fileName
     * @param reqWidth
     * @param reqHeight
     * @return a bitmap decoded from the specified file
     */
    public synchronized static Bitmap decodeSampledBitmapFromFileName(String fileName, int reqWidth, int reqHeight) {
        try {
            // First decode with inJustDecodeBounds=true to check dimensions
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(fileName, options);
//            Calculate inSampleSize
            options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);

            // Decode bitmap with inSampleSize set
            options.inJustDecodeBounds = false;
            return BitmapFactory.decodeFile(fileName, options);

        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }

        return null;
    }

    public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
        // Raw height and width of image
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;

        if (height > reqHeight || width > reqWidth) {

            final int halfHeight = height / 2;
            final int halfWidth = width / 2;

            // Calculate the largest inSampleSize value that is a power of 2 and keeps both
            // height and width larger than the requested height and width.
            while ((halfHeight / inSampleSize) > reqHeight
                    && (halfWidth / inSampleSize) > reqWidth) {
                inSampleSize *= 2;
            }
        }

        return inSampleSize;
    }

    /**
     * 读取照片exif信息中的旋转角度<br>http://www.eoeandroid.com/thread-196978-1-1.html
     *
     * @param path 照片路径
     * @return角度
     */
    public static int readPictureDegree(String path) {
        int degree = 0;
        try {
            ExifInterface exifInterface = new ExifInterface(path);
            int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
            switch (orientation) {
                case ExifInterface.ORIENTATION_ROTATE_90:
                    degree = 90;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_180:
                    degree = 180;
                    break;
                case ExifInterface.ORIENTATION_ROTATE_270:
                    degree = 270;
                    break;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return degree;
    }

    /**
     * 根据旋转角度选择图片
     *
     * @param bitmap
     * @param degree
     * @param recycleOrig
     * @return
     */
    public synchronized static Bitmap setRotate(Bitmap bitmap, int degree, boolean recycleOrig) {
        try {
            Matrix matrix = new Matrix();
            //设置图像的旋转角度
            matrix.setRotate(degree);
            //旋转图像，并生成新的Bitmap对像
            Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

            if (recycleOrig && bitmap != null && !bitmap.isRecycled())
                bitmap.recycle();

            return newBitmap;

        } catch (OutOfMemoryError e) {
            e.printStackTrace();
        }

        return bitmap;
    }

    /**
     * 获取图片文件的信息，是否旋转了90度，如果是则反转
     *
     * @param bitmap 需要旋转的图片
     * @param path   图片的路径
     */
    public static Bitmap reviewPicRotate(Bitmap bitmap, String path) {
        int degree = readPictureDegree(path);
        if (degree != 0) {
            Matrix m = new Matrix();
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            m.setRotate(degree); // 旋转angle度
            bitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, m, true);// 从新生成图片
        }
        return bitmap;
    }

    public static Bitmap compressImageByPath(String path) {
        Bitmap bitmap = null;

        File file = new File(path);
        if (file != null) {
            bitmap = getImageThumbnail(path, MAX_HEIGHT, MAX_WIDTH); // 根据限定最大尺寸进行b比特率压缩
            if (bitmap != null) {// 质量压缩
                if (bitmap.getHeight() / bitmap.getWidth() > 2.5) {
                    bitmap = compressBitmap(bitmap, MAX_K_LONG_SIZE);
                } else {
                    bitmap = compressBitmap(bitmap, MAX_K_SIZE);
                }
            }

        }
        Log.e("resultSize", bitmap.getByteCount() + "");

        return bitmap;
    }

    public static byte[] getBitmapByteArrayFromPath(String absolutePath) {
        Bitmap bitmap = null;
        byte[] bytes = null;

        File file = new File(absolutePath);
        if (null != file) {
            bitmap = getImageThumbnail(absolutePath, MAX_HEIGHT, MAX_WIDTH); // 根据限定最大尺寸进行b比特率压缩
            bitmap = reviewPicRotate(bitmap, absolutePath);
            bytes = convertBitmapToByteArrayByOptions(bitmap, 70);           // 根据70%压缩图片
            recycleBitmap(bitmap);
        }

        return bytes;
    }

    private static Bitmap getImageThumbnail(String filePath, int imgHeight, int imgWidth) {
        Bitmap bitmap = null;

        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 1;
        options.inJustDecodeBounds = true;
        bitmap = BitmapFactory.decodeFile(filePath, options);
        // 计算图片缩放比例
        final int minSideLength = Math.min(imgWidth, imgHeight);
        options.inSampleSize = computeSampleSize(options, minSideLength,
                imgWidth * imgHeight);

        options.inJustDecodeBounds = false;
        options.inPreferredConfig = Bitmap.Config.RGB_565;
        try {
            bitmap = BitmapFactory.decodeFile(filePath, options);
        } catch (OutOfMemoryError error) {
            System.gc();
            bitmap = BitmapFactory.decodeFile(filePath, options);
        } finally {
            return bitmap;
        }
    }

    public static int computeSampleSize(BitmapFactory.Options options,
                                        int minSideLength, int maxNumOfPixels) {
        int initialSize = computeInitialSampleSize(options, minSideLength,
                maxNumOfPixels);

        int roundedSize;
        if (initialSize <= 8) {
            roundedSize = 1;
            while (roundedSize < initialSize) {
                roundedSize <<= 1;
            }
        } else {
            roundedSize = (initialSize + 7) / 8 * 8;
        }

        return roundedSize;
    }

    private static int computeInitialSampleSize(BitmapFactory.Options options,
                                                int minSideLength, int maxNumOfPixels) {
        double w = options.outWidth;
        double h = options.outHeight;

        int lowerBound = (maxNumOfPixels == -1) ? 1 : (int) Math.ceil(Math
                .sqrt(w * h / maxNumOfPixels));
        int upperBound = (minSideLength == -1) ? 128 : (int) Math.min(Math
                .floor(w / minSideLength), Math.floor(h / minSideLength));

        if (upperBound < lowerBound) {
            // return the larger one when there is no overlapping zone.
            return lowerBound;
        }

        if ((maxNumOfPixels == -1) && (minSideLength == -1)) {
            return 1;
        } else if (minSideLength == -1) {
            return lowerBound;
        } else {
            return upperBound;
        }
    }

    private static Bitmap compressBitmap(Bitmap image, int maxKSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 90;
        while ((baos.size() / 1024) > maxKSize) {    //循环判断如果压缩后图片是否大于maxKSize kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%，把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }

        ByteArrayInputStream isBm = new ByteArrayInputStream(baos.toByteArray());//把压缩后的数据baos存放到ByteArrayInputStream中
        return BitmapFactory.decodeStream(isBm, null, null);//把ByteArrayInputStream数据生成图片
    }

    private static byte[] compressBitmapToByte(Bitmap image, int maxKSize) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 90;
        while ((baos.size() / 1024) > maxKSize && options >= 0) {    //循环判断如果压缩后图片是否大于maxKSize kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%，把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }
        return baos.toByteArray();
    }

    /* 按照options %压缩质量 */
    public static byte[] convertBitmapToByteArrayByOptions(Bitmap image, int options) {
        if (image == null) {
            return null;
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, options, baos);//质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        byte[] bytes = baos.toByteArray();
        IOUtils.closeCloseable(baos);
        return bytes;
    }

    /* 根据最大质量限定进行压缩 */
    public static byte[] convertBitmapToByteArrayByMaxSize(Bitmap image, int maxKSize) {
        if (image == null) {
            return null;
        }

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        image.compress(Bitmap.CompressFormat.JPEG, 100, baos);//质量压缩方法，这里100表示不压缩，把压缩后的数据存放到baos中
        int options = 90;
        while ((baos.size() / 1024) > maxKSize) {    //循环判断如果压缩后图片是否大于maxKSize kb,大于继续压缩
            baos.reset();//重置baos即清空baos
            image.compress(Bitmap.CompressFormat.JPEG, options, baos);//这里压缩options%，把压缩后的数据存放到baos中
            options -= 10;//每次都减少10
        }

        byte[] bytes = baos.toByteArray();
        IOUtils.closeCloseable(baos);
        return bytes;
    }

    /* 根据Bitmap的option判断是否为空 */
    public static boolean isBitmapEmpty(String path) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inSampleSize = 1;
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        return options.outHeight <= 0 || options.outWidth <= 0;
    }

    /**
     * 根据规定的图片大小来获取图片。以最大比为准
     *
     * @param filePath
     * @param targetWidth
     * @param targetHeight
     * @return
     */
    public static Bitmap compressBySize(String filePath, int targetWidth, int targetHeight) {
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, opts);
        // 得到图片的宽度、高度；
        int imgWidth = opts.outWidth;
        int imgHeight = opts.outHeight;
        // 分别计算图片宽度、高度与目标宽度、高度的比例；取大于等于该比例的最小整数；
        int widthRatio = (int) Math.ceil(imgWidth / (float) targetWidth);
        int heightRatio = (int) Math.ceil(imgHeight / (float) targetHeight);
        if (widthRatio > 1 || heightRatio > 1) {
            if (widthRatio > heightRatio) {
                opts.inSampleSize = widthRatio;
            } else {
                opts.inSampleSize = heightRatio;
            }
        }
        // 设置好缩放比例后，加载图片进内容；
        opts.inJustDecodeBounds = false;
        opts.inPreferredConfig = Bitmap.Config.RGB_565;
        try {
            bitmap = BitmapFactory.decodeFile(filePath, opts);
        } catch (OutOfMemoryError e) {
            LogUtil.e("BitmapUtils", "compressBySize has error of " + e.getLocalizedMessage());
            return null;
        }
        return bitmap;
    }

    /**
     * 通过降低图片的质量来压缩图片
     *
     * @param bitmap
     * @param quality
     * @return
     */
    public static String compressByQuality(Bitmap bitmap, int quality) {
        if (bitmap == null)
            return null;

        String filename = System.currentTimeMillis() + ".jpg";
        File jpgFile = FileUtils.createFile(Cache.getUploadImageFileDictory(), filename);
        FileOutputStream outputStream = null; // 文件输出流
        try {
            outputStream = new FileOutputStream(jpgFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            outputStream.flush();
            outputStream.close(); // 关闭输出流
            recycleBitmap(bitmap);
            return jpgFile.getPath();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 通过降低图片质量和图片尺寸来压缩图片，指定图片最小边的最大尺寸、压缩质量
     *
     * @param filePath
     * @param maxLength
     * @param quality
     * @return
     */
    public static File compressByQualityAndSize(String filePath, int maxLength, int quality) {
        /*----- 尺寸、文件压缩 -----*/
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, opts);
        // 得到图片的宽度、高度；
        int imgWidth = opts.outWidth;
        int imgHeight = opts.outHeight;
        float rate = 1f;
        if (imgWidth > imgHeight && imgHeight > maxLength) {
            rate = maxLength / (float) imgHeight;
        } else if (imgWidth <= imgHeight && imgWidth > maxLength) {
            rate = maxLength / (float) imgWidth;
        }
        // 设置好缩放比例后，加载图片进内容；
        opts.inJustDecodeBounds = false;
        opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
        Bitmap resizeBitmap = null;
        try {
            bitmap = BitmapFactory.decodeFile(filePath, opts);
            if (rate != 1) {
                // 创建操作图片的matrix对象
                Matrix matrix = new Matrix();
                // 缩放图片动作
                matrix.postScale(rate, rate);
                resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, imgWidth, imgHeight, matrix, true);
            }
        } catch (OutOfMemoryError e) {
            LogUtil.e("BitmapUtils", "compressBySize has error of " + e.getLocalizedMessage());
            return null;
        }

        if (resizeBitmap != null) {
            recycleBitmap(bitmap);
            bitmap = resizeBitmap;
        }
        /*----- 质量压缩 -----*/
        String filename = System.currentTimeMillis() + ".jpg";
        File jpgFile = FileUtils.createFile(Cache.getUploadImageFileDictory(), filename);
        FileOutputStream outputStream; // 文件输出流
        try {
            outputStream = new FileOutputStream(jpgFile);
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            outputStream.flush();
            outputStream.close(); // 关闭输出流
            recycleBitmap(bitmap);
            recycleBitmap(resizeBitmap);
            return jpgFile;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过降低图片质量和图片尺寸来压缩图片，指定图片最小边的最大尺寸、最大文件大小
     *
     * @param filePath
     * @param maxLength
     * @param maxKSize
     * @return
     */
    public static File compressByFileSizeAndSize(String filePath, int maxLength, int maxKSize) {
        /*----- 尺寸、文件压缩 -----*/
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(filePath, opts);
        // 得到图片的宽度、高度；
        int imgWidth = opts.outWidth;
        int imgHeight = opts.outHeight;
        float rate = 1f;
        if (imgWidth > imgHeight && imgHeight > maxLength) {
            rate = maxLength / (float) imgHeight;
        } else if (imgWidth <= imgHeight && imgWidth > maxLength) {
            rate = maxLength / (float) imgWidth;
        }
        // 设置好缩放比例后，加载图片进内容；
        opts.inJustDecodeBounds = false;
        opts.inPreferredConfig = Bitmap.Config.ARGB_8888;
        Bitmap resizeBitmap = null;
        try {
            bitmap = BitmapFactory.decodeFile(filePath, opts);
            if (rate != 1) {
                // 创建操作图片的matrix对象
                Matrix matrix = new Matrix();
                // 缩放图片动作
                matrix.postScale(rate, rate);
                resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, imgWidth, imgHeight, matrix, true);
            }
        } catch (OutOfMemoryError e) {
            LogUtil.e("BitmapUtils", "compressBySize has error of " + e.getLocalizedMessage());
            return null;
        }

        if (resizeBitmap != null) {
            recycleBitmap(bitmap);
            bitmap = resizeBitmap;
        }
        /*----- 质量压缩 -----*/
        String filename = System.currentTimeMillis() + ".jpg";
        File jpgFile = FileUtils.createFile(Cache.getUploadImageFileDictory(), filename);
        FileOutputStream outputStream; // 文件输出流
        try {
            outputStream = new FileOutputStream(jpgFile);
            outputStream.write(compressBitmapToByte(bitmap, maxKSize));
            outputStream.flush();
            outputStream.close(); // 关闭输出流
            recycleBitmap(bitmap);
            recycleBitmap(resizeBitmap);
            return jpgFile;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {

        }
        return null;
    }


    public static void recycleBitmap(Bitmap bitmap) {
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
            bitmap = null;
            System.gc();
        }
    }

    /* 根据文件路径转化成字符流 */
    public static String getBitmapStringFromPath(String absolutePath) {
        Bitmap bitmap = null;
        String bitmapStrings = "";
        File file = new File(absolutePath);
        if (file != null && file.exists()) {
            bitmap = getImageThumbnail(absolutePath, MAX_HEIGHT, MAX_WIDTH); // 根据限定最大尺寸进行b比特率压缩
            bitmap = reviewPicRotate(bitmap, absolutePath);
            bitmapStrings = bitmapToString(bitmap, 70);
            recycleBitmap(bitmap);
        }
        return bitmapStrings;
    }

    // 把bitmap转换成String
    public static String bitmapToString(Bitmap bm, int rate) {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bm.compress(Bitmap.CompressFormat.JPEG, rate, baos);
        byte[] b = baos.toByteArray();
        return Base64.encodeToString(b, Base64.DEFAULT);
    }

    /**
     * 获取本地drawable 转换到bitmap
     *
     * @param resId
     * @param width
     * @param height
     * @return
     */
    public static Bitmap getBitMapFromDrawable(Context context, int resId, int width, int height) {
        Bitmap bm = BitmapFactory.decodeResource(context.getResources(), resId);
        if (width <= 0 || height <= 0) {
            return bm;
        }
        return Bitmap.createScaledBitmap(bm, width, height, false);
    }

    /* 设置bitmap的透明度 */
    public static Bitmap setAlpha(Bitmap sourceImg, int number) {
        int[] argb = new int[sourceImg.getWidth() * sourceImg.getHeight()];
        sourceImg.getPixels(argb, 0, sourceImg.getWidth(), 0, 0, sourceImg.getWidth(), sourceImg.getHeight());
        // 获得图片的ARGB值
        number = number * 255 / 100;
        for (int i = 0; i < argb.length; i++) {
            if (argb[i] != 0) {
                argb[i] = (number << 24) | (argb[i] & 0x00FFFFFF);
            }
            // 修改最高2位的值
        }
        sourceImg = Bitmap.createBitmap(argb, sourceImg.getWidth(), sourceImg.getHeight(), Bitmap.Config.ARGB_8888);
        return sourceImg;
    }

}
